/**
 * 
 */
package hu.gbalage.owlforms.xforms.gen;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import hu.gbalage.owlforms.api.Field;
import hu.gbalage.owlforms.api.FieldCardinality;
import hu.gbalage.owlforms.api.Form;
import hu.gbalage.owlforms.api.style.FieldTitleProvider;
import hu.gbalage.owlforms.api.style.OWLFormsStyle;
import hu.gbalage.owlforms.xforms.XMLHelper;

/**
 * @author Grill Balazs (balage.g@gmail.com)
 *
 */
public class DescriptedXFormsSerializer implements FormSerializer {

	public static final String NS_XHTML = "http://www.w3.org/1999/xhtml";
	public static final String NS_EVENT = "http://www.w3.org/2001/xml-events";
	public static final String NS_XFORMS = "http://www.w3.org/2002/xforms";
	
	public static final String NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns";
	public static final String NS_RDFS = "http://www.w3.org/2000/01/rdf-schema";
	public static final String NS_OWL = "http://www.w3.org/2002/07/owl";
	public static final String NS_XSD = "http://www.w3.org/2001/XMLSchema";
	
	protected final String action;
	
	public DescriptedXFormsSerializer(String action){
		this.action = action;
	}
	
	public class State implements SerializationState{
		
		Document doc;
		
		Element root;
		
		Element body;
		Element model;
		
		OWLFormsStyle style; 
		
		Element modelplace;
		
		Element viewplace;
		
		String xpath;
		
		int repeats;
		
		@Override
		public Document getDocument() {
			return doc;
		}
		
		public State copy(){
			State s = new State();
			s.doc = doc;
			s.root = root;
			s.style = style;
			s.modelplace = modelplace;
			s.viewplace = viewplace;
			s.xpath = xpath;
			s.body = body;
			s.model = model;
			s.repeats = repeats;
			return s;
		}
		
	}
	
	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.xforms.gen.FormSerializer#initState()
	 */
	@Override
	public SerializationState initState(Form form) {
		State state = new State();
		
		state.style = form.getStyle();
		state.repeats = 0;
		
		Document doc = XMLHelper.createEmptyDoc();
		
		Element html = doc.createElementNS(NS_XHTML, "html");
		html.setAttribute("xmlns", NS_XHTML);
		html.setAttribute("xmlns:xhtml", NS_XHTML);
		//html.setAttribute("xmlns:rdf", NS_RDF);
		html.setAttribute("xmlns:xf", NS_XFORMS);
		html.setAttribute("xmlns:e", NS_EVENT);
		//html.setAttribute("xmlns:rdfs", NS_RDFS);
		//html.setAttribute("xmlns:owl", NS_OWL);
		//html.setAttribute("xmlns:xsd", NS_XSD);
		doc.appendChild(html);
		
		Element head = doc.createElement("xhtml:head");
		html.appendChild(head);
		
		Element title = doc.createElement("xhtml:title");
		title.setTextContent(state.style.getFieldTitleProvider().getTitle(form));
		head.appendChild(title);
		
		Element style = doc.createElement("xhtml:link");
		style.setAttribute("rel", "stylesheet");
		style.setAttribute("type", "text/css");
		style.setAttribute("href", "style.css");
		head.appendChild(style);
		
		Element body = doc.createElement("xhtml:body");
		html.appendChild(body);
		
		Element h1title = doc.createElement("xhtml:h1");
		h1title.setTextContent(state.style.getFieldTitleProvider().getTitle(form));
		body.appendChild(h1title);
		
		Element model = doc.createElement("xf:model");
		model.setAttribute("id", "default");
		head.appendChild(model);
		
		Element instance = doc.createElement("xf:instance");
		instance.setAttribute("xmlns", "");
		model.appendChild(instance);

		state.model = model;
		state.doc = doc;
		state.body = body;
		state.root = html;
		state.modelplace = instance;
		state.viewplace = body;
		state.xpath = "/";
		
		return state;
	}

	protected Element br(Document doc){
		return doc.createElement("xhtml:br");
	}
	
	private int repeatid = 0;
	
	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.xforms.gen.FormSerializer#serializeField(hu.gbalage.owlforms.api.Field, hu.gbalage.owlforms.xforms.gen.SerializationState)
	 */
	@Override
	public SerializationState serializeField(Field field,
			SerializationState state) {
		
		FieldCardinality cardinality = field.getCardinality();
		
		State s = (State)state;
		Element modelplace = s.modelplace;
		Element viewplace = s.viewplace;
		Document doc = s.doc;

		Element fieldmodel = doc.createElement("fielddata");
		Element value = doc.createElement("value");
		fieldmodel.setAttribute("uri", field.getURI().toString());
		fieldmodel.appendChild(value);
		modelplace.appendChild(fieldmodel);
				
		if (field.isComplex()){
			
			if (field.asComplexField().isImported()){
				value.setAttribute("input", "uri");				
			}else{
			
			State ns = s.copy();
			
			Element fmodel = doc.createElement("xhtml:h2");
			fmodel.setTextContent(s.style.getFieldTitleProvider().getTitle(field));
			viewplace.appendChild(fmodel);
			
			Element repeat = doc.createElement("xf:repeat");
			
			String repeatset =  ns.xpath+"fielddata[@uri='"+field.getURI()+"']"; 
			
			repeat.setAttribute("nodeset",repeatset+"/value");
			repeat.setAttribute("id", "repeat"+repeatid);
			
			viewplace.appendChild(repeat);	
			
			if (cardinality.getMax() > 1){
				Element addbutton = doc.createElement("xf:trigger");
				Element addlabel = doc.createElement("xf:label");
					addlabel.setTextContent("+");
					addbutton.appendChild(addlabel);
				Element action = doc.createElement("xf:action");
					action.setAttribute("e:event", "DOMActivate");
				Element addaction = doc.createElement("xf:insert");
					addaction.setAttribute("context", repeatset);
					addaction.setAttribute("nodeset", "value");
					addaction.setAttribute("at", "last()");
					addaction.setAttribute("position", "after");
					action.appendChild(addaction);
					addbutton.appendChild(action);
				viewplace.appendChild(addbutton);
				
				Element removebutton = doc.createElement("xf:trigger");
				Element removelabel = doc.createElement("xf:label");
					removelabel.setTextContent("-");
					removebutton.appendChild(removelabel);
				Element delaction = doc.createElement("xf:action");
					delaction.setAttribute("e:event", "DOMActivate");
					removebutton.appendChild(delaction);
				Element removeaction = doc.createElement("xf:delete");
					removeaction.setAttribute("nodeset", "../value");
					removeaction.setAttribute("at", "index('"+repeatid+"')");
					removeaction.setAttribute("if", "not(last()=1)");
					delaction.appendChild(removeaction);
					repeat.appendChild(removebutton);
			}
			repeatid++;
			
			Element div = doc.createElement("xhtml:div");
			div.setAttribute("class", "switch");
			repeat.appendChild(div);
			
			//Create buttons to change case
			Form[] forms = field.asComplexField().getContainedForm();
			if (forms.length > 1){
				Element buttons = doc.createElement("xhtml:div");
				buttons.setAttribute("class", "buttons");
				div.appendChild(buttons);
				
				String[] ids = new String[forms.length];
				for(int i=0;i<ids.length;i++){
					ids[i] = "case"+ns.repeats+"_"+forms[i].getURI().getFragment();
				}
				
				for(int i=0;i<ids.length;i++){
					Form one = forms[i];
					Element trigger = doc.createElement("xf:trigger");
					buttons.appendChild(trigger);
					Element triggerlabel = doc.createElement("xf:label");
					trigger.appendChild(triggerlabel);
					triggerlabel.setTextContent(one.getStyle().getFieldTitleProvider().getTitle(one));
					
					Element action = doc.createElement("xf:action");
					trigger.appendChild(action);
					action.setAttribute("e:event", "DOMActivate");
					
					Element toggle = doc.createElement("xf:toggle");
					action.appendChild(toggle);
					toggle.setAttribute("case", ids[i]);
					for(int j=0;j<ids.length;j++){
						Element setvalue = doc.createElement("xf:setvalue");
						setvalue.setAttribute("ref", "formdata[@uri='"+forms[j].getURI()+"']/@selected");
						setvalue.setTextContent((i==j)?"true":"false");
						action.appendChild(setvalue);
					}
				}
			}
			
			Element xfswitch = doc.createElement("xf:switch");
			div.appendChild(xfswitch);
			
			ns.repeats++;
			ns.xpath = "";
			ns.modelplace = value;
			ns.viewplace = xfswitch;
			return ns;
			}
			return null;
		}else{
			if (!field.isDerivative()){
				Element inputdiv = doc.createElement("xhtml:div");
				inputdiv.setAttribute("class", "input");
				FieldTitleProvider title = s.style.getFieldTitleProvider();
				Element input = doc.createElement("xf:input");
				input.setAttribute("ref", s.xpath+"fielddata[@uri='"+field.getURI()+"']/value");
				inputdiv.appendChild(input);
				Element label = doc.createElement("xf:label");
				label.setTextContent(title.getTitle(field)+":");
				input.appendChild(label);
				//viewplace.appendChild(br(doc));
				viewplace.appendChild(inputdiv);
			}
			return null;
		}
	}

	/* (non-Javadoc)
	 * @see hu.gbalage.owlforms.xforms.gen.FormSerializbalageeg@hotmail.com bontotta a kapcsolatoter#serializeForm(hu.gbalage.owlforms.api.Form, hu.gbalage.owlforms.xforms.gen.SerializationState)
	 */
	@Override
	public SerializationState serializeForm(Form form, SerializationState state, Boolean selected) {
		State s = (State)state;
		Element modelplace = s.modelplace;
		Element viewplace = s.viewplace;
		Document doc = s.doc;
		
		
		Element formmodel = doc.createElement("formdata");//createEntityNode(doc, form);
		formmodel.setAttribute("uri", form.getURI().toString());
		modelplace.appendChild(formmodel);
		
		//Element group = doc.createElement("xf:group");
		//String refns = getPrefix(formmodel.getNamespaceURI());
		//group.setAttribute("ref", /*refns+":"+*/formmodel.getTagName());
		//viewplace.appendChild(group);
		
		if (selected != null){
			
			formmodel.setAttribute("selected", ""+selected);
			
			Element xfcase = doc.createElement("xf:case");
			xfcase.setAttribute("id", "case"+(s.repeats-1)+"_"+form.getURI().getFragment());
			xfcase.setAttribute("selected", ""+selected);
			viewplace.appendChild(xfcase);
			viewplace = xfcase;
		}
		
		State ns = s.copy();
		ns.xpath += "formdata[@uri='"+form.getURI()+"']/";
		ns.viewplace = viewplace;
		ns.modelplace = formmodel;
		
		return ns;
	}

	@Override
	public void putInputDiv(SerializationState state) {
		State s = (State)state;
		Element div = s.doc.createElement("xhtml:div");
		s.viewplace.appendChild(div);
		div.setAttribute("class", "import");
	}
	
	@Override
	public SerializationState finalize(SerializationState state) {
		State s = (State)state;
		Document doc = s.doc;
		Element model = s.model;
		Element body = s.body;
		
		Element submission = doc.createElement("xf:submission");
		submission.setAttribute("id","post");
		submission.setAttribute("method","post");
		submission.setAttribute("action", action);
		model.appendChild(submission);
		
		Element submit = doc.createElement("xf:submit");
		submit.setAttribute("submission", "post");
		body.appendChild(submit);
		
		Element label = doc.createElement("xf:label");
		label.setTextContent("Elküld");
		submit.appendChild(label);
		
		return state;
	}
	
}
